package com.simple.portal.bo.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.mail.MessagingException;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import com.simple.portal.bo.ISendMailBO;
import com.simple.portal.dao.IUserInfoDAO;
import com.simple.portal.vo.UserInfoVO;
import com.simple.util.EmailUtil;
import com.simple.util.common.Constants;
import com.simple.util.common.EncryptUtil;
import com.simple.util.common.LocaleUtil;
import com.simple.util.exception.SimpleApplicationException;
import com.simple.util.exception.SimpleSystemException;
import com.simple.util.object.EmailConfigBean;

import freemarker.template.Template;
import freemarker.template.TemplateException;

@Service("portalSendMailBO")
@Transactional(propagation=Propagation.REQUIRED,readOnly=true)
public class SendMailBOImpl implements ISendMailBO {
	private static final Logger LOG = Logger
			.getLogger(SendMailBOImpl.class);

	private static final String EMAIL_NOTIFY_CONFIG_FILE = "/email/email_notify_config.xml";

	private final Map<String, EmailConfigBean> emailConfigMap;

	@Autowired
	private FreeMarkerConfigurer freeMarkerConfigurer;
	
	@Autowired
	private IUserInfoDAO userInfoDAO;

	@Override
	@Transactional(propagation=Propagation.REQUIRED,readOnly=false,rollbackFor={Exception.class})
	public void sendRegisterAckMail(final String siteLanguage,
			final String userId, final String operator) throws SimpleApplicationException {
		final UserInfoVO userInfoVO= userInfoDAO.findById(userId);

		Map<String, String> map = new HashMap<String, String>();
		map.put("userName", userInfoVO.getUsername());
		map.put("loginId", EncryptUtil.decrypt(userInfoVO.getLoginId()));
		final String password = EncryptUtil.getRandomPassword();
		map.put("password", password);

		sendMail("REGISTER_ACK",siteLanguage,userInfoVO.getEmailAddress(), map);
		
		userInfoVO.setPassword(EncryptUtil.passwordEncryptor(password));
		userInfoVO.setInitPasswordFlag(Constants.STATE_YES);
		userInfoDAO.update(userInfoVO,Constants.LOGGER_OPERATE_FLAG_UPDATE, operator);

	}
	
	
	@Override
	@Transactional(propagation=Propagation.REQUIRED,readOnly=false,rollbackFor={Exception.class})
	public void sendPasswordResetMail(final String siteLanguage,
			final String userId, final String operator) throws SimpleApplicationException {
		
		final UserInfoVO userInfoVO= userInfoDAO.findById(userId);
		Map<String, String> map = new HashMap<String, String>();
		map.put("userName", userInfoVO.getUsername());
		map.put("loginId", EncryptUtil.decrypt(userInfoVO.getLoginId()));
		final String password = EncryptUtil.getRandomPassword();
		map.put("password", password);
		
		userInfoVO.setPassword(EncryptUtil.passwordEncryptor(password));
		userInfoVO.setInitPasswordFlag(Constants.STATE_YES);
		userInfoDAO.update(userInfoVO, Constants.LOGGER_OPERATE_FLAG_UPDATE, operator);
		
		sendMail("PASSWORD_RESET", siteLanguage, userInfoVO.getEmailAddress(), map);

	}
	

	private void sendMail(final String emailId, final String siteLanguage,final String toMail, final Object map) throws SimpleApplicationException {
		final EmailConfigBean emailConfigBean;
		if (emailConfigMap.containsKey(emailId + siteLanguage)) {
			emailConfigBean = emailConfigMap.get(emailId + siteLanguage);
		} else {
			emailConfigBean = emailConfigMap.get(emailId);
		}
		if (emailConfigBean == null) {
			throw new SimpleApplicationException("message.email.config.not.exist",new String[]{emailId});
		}
		
		try {
			final Template template = freeMarkerConfigurer.getConfiguration()
					.getTemplate(emailConfigBean.getTemplate(),
							LocaleUtil.toLocaleFromStr(siteLanguage));
	
			final String mailContent = FreeMarkerTemplateUtils
					.processTemplateIntoString(template, map);
	
			EmailUtil.sendHtmlEmail(emailConfigBean.getSenderemail()+"("+emailConfigBean.getSendername()+")", toMail,
					null, emailConfigBean.getSubject(), mailContent);
		} catch (IOException e) {
			throw new SimpleSystemException("message.email.send.error", e);
		} catch (TemplateException e) {
			throw new SimpleSystemException("message.email.send.error", e);
		} catch (MessagingException e) {
			throw new SimpleSystemException("message.email.send.error", e);
		}
	}

	public SendMailBOImpl() {
		InputStream inStream = null;
		Element root = null;
		try {
			inStream = new ClassPathResource(EMAIL_NOTIFY_CONFIG_FILE)
					.getInputStream();
			final SAXReader reader = new SAXReader();
			final Document doc = reader.read(inStream);
			root = doc.getRootElement();
		} catch (IOException e) {
			throw new SimpleSystemException("message.system.error", e);
		} catch (DocumentException e) {
			throw new SimpleSystemException("message.system.error", e);
		} finally {
			if (inStream != null) {
				try {
					inStream.close();
				} catch (IOException e) {
					LOG.error(e.getMessage(), e);
				}
			}
		}

		emailConfigMap = loadEmailConfig(root);
	}

	@SuppressWarnings("unchecked")
	private Map<String, EmailConfigBean> loadEmailConfig(final Element root) {
		final Map<String, EmailConfigBean> map = new HashMap<String, EmailConfigBean>();
		final Element parentNode = root.element("notify-configs");

		if (parentNode != null) {
			for (final Iterator<Element> iter = parentNode
					.elementIterator("email-config"); iter.hasNext();) {
				final Element element = (Element) iter.next();
				final EmailConfigBean bean = new EmailConfigBean();
				bean.setId(getNodeValue("id", element));
				bean.setLocale(getNodeValue("locale", element));
				bean.setSendername(getNodeValue("sendername", element));
				bean.setSenderemail(getNodeValue("senderemail", element));
				bean.setSubject(getNodeValue("subject", element));
				bean.setTemplate(getNodeValue("template", element));
				map.put(bean.getId() + bean.getLocale(), bean);
			}
		}

		return map;
	}

	private String getNodeValue(final String nodeName, final Element element) {
		return element.elementText(nodeName);
	}
}
